// Copyright (c) 2024 CHANGLEI. All rights reserved.

import 'dart:ui';

import 'package:charts_grasp/src/circular_chart/base/circular_state_properties.dart';
import 'package:charts_grasp/src/circular_chart/renderer/chart_point.dart';
import 'package:charts_grasp/src/circular_chart/renderer/circular_series.dart';
import 'package:charts_grasp/src/circular_chart/renderer/renderer_base.dart';
import 'package:charts_grasp/src/circular_chart/renderer/renderer_extension.dart';
import 'package:charts_grasp/src/circular_chart/utils/helper.dart';

class CircularSeriesController {
  CircularSeriesController(this.seriesRenderer);

  late final CircularSeriesRenderer seriesRenderer;

  void updateDataSource(
      {List<int>? addedDataIndexes,
      List<int>? removedDataIndexes,
      List<int>? updatedDataIndexes,
      int? addedDataIndex,
      int? removedDataIndex,
      int? updatedDataIndex,}) {
    if (removedDataIndexes != null && removedDataIndexes.isNotEmpty) {
      _removeDataPointsList(removedDataIndexes);
    } else if (removedDataIndex != null) {
      _removeDataPoint(removedDataIndex);
    }
    if (addedDataIndexes != null && addedDataIndexes.isNotEmpty) {
      _addOrUpdateDataPoints(addedDataIndexes, false);
    } else if (addedDataIndex != null) {
      _addOrUpdateDataPoint(addedDataIndex, false);
    }
    if (updatedDataIndexes != null && updatedDataIndexes.isNotEmpty) {
      _addOrUpdateDataPoints(updatedDataIndexes, true);
    } else if (updatedDataIndex != null) {
      _addOrUpdateDataPoint(updatedDataIndex, true);
    }
    _updateCircularSeries();
  }

  void _addOrUpdateDataPoints(List<int> indexes, bool needUpdate) {
    int dataIndex;
    for (int i = 0; i < indexes.length; i++) {
      dataIndex = indexes[i];
      _addOrUpdateDataPoint(dataIndex, needUpdate);
    }
  }

  void _addOrUpdateDataPoint(int index, bool needUpdate) {
    final CircularSeriesRendererExtension renderer = seriesRenderer as CircularSeriesRendererExtension;
    final CircularSeries<dynamic, dynamic> series = renderer.series;
    if (index >= 0 && series.dataSource!.length > index && series.dataSource![index] != null) {
      final ChartPoint<dynamic> currentPoint = getCircularPoint(renderer, index);
      if (currentPoint.x != null) {
        if (needUpdate) {
          if (renderer.dataPoints.length > index) {
            renderer.dataPoints[index] = currentPoint;
          }
        } else {
          if (renderer.dataPoints.length == index) {
            renderer.dataPoints.add(currentPoint);
          } else if (renderer.dataPoints.length > index && index >= 0) {
            renderer.dataPoints.insert(index, currentPoint);
          }
        }
      }
    }
  }

  void _removeDataPointsList(List<int> removedDataIndexes) {
    final List<int> indexList = removedDataIndexes.toSet().toList();
    indexList.sort((b, a) => a.compareTo(b));
    int dataIndex;
    for (int i = 0; i < indexList.length; i++) {
      dataIndex = indexList[i];
      _removeDataPoint(dataIndex);
    }
  }

  void _removeDataPoint(int index) {
    final CircularSeriesRendererExtension renderer = seriesRenderer as CircularSeriesRendererExtension;
    if (renderer.dataPoints.isNotEmpty && index >= 0 && index < renderer.dataPoints.length) {
      renderer.dataPoints.removeAt(index);
    }
  }

  void _updateCircularSeries() {
    final CircularSeriesRendererExtension renderer = seriesRenderer as CircularSeriesRendererExtension;
    final CircularStateProperties stateProperties = renderer.stateProperties;
    stateProperties.chartSeries.processDataPoints(renderer);
    stateProperties.chartSeries.calculateAngleAndCenterPositions(renderer);
    renderer.repaintNotifier.value++;
    if (renderer.series.dataLabelSettings.isVisible && stateProperties.renderDataLabel != null) {
      stateProperties.renderDataLabel!.state.render();
    }
    if (renderer.series.dataLabelSettings.isVisible && stateProperties.renderingDetails.chartTemplate != null) {
      stateProperties.renderingDetails.chartTemplate!.state.templateRender();
    }
  }


  ChartPoint<dynamic> pixelToPoint(Offset position) {
    final CircularSeriesRendererExtension renderer = seriesRenderer as CircularSeriesRendererExtension;
    return circularPixelToPoint(position, renderer.stateProperties);
  }
}
